#pragma once

#include "njm_component.hpp"
#include "njm_component_array.hpp"
#include <unordered_map>
#include <memory>
#include <typeinfo>
#include <string>

namespace njm
{
    class ComponentManager
    {
    public:
        ComponentManager();
        ~ComponentManager();
        void Init();
        void Clear();
        //
        template <typename T>
        void RegisterComponent()
        {
            const char *typeName = typeid(T).name();
            assert(mComponentTypes.find(typeName) == mComponentTypes.end() && "Registering component type more than once.");
            // 把新的ComponentType加入映射, 创建新的ComponentArray，并将其加入映射
            mComponentTypes.insert({typeName, mNextComponentType});
            mComponentArrays.insert({typeName, std::make_shared<ComponentArray<T>>()});
            ++mNextComponentType;
        }

        template <typename T>
        ComponentType GetComponentType()
        {
            const char *typeName = typeid(T).name();
            assert(mComponentTypes.find(typeName) != mComponentTypes.end() && "Component not registered before use.");
            return mComponentTypes[typeName];
        }

        template <typename T>
        Signature GetComponentSignature()
        {
            const char *typeName = typeid(T).name();
            assert(mComponentTypes.find(typeName) != mComponentTypes.end() && "Component not registered before use.");
            ComponentType transformType = mComponentTypes[typeName];
            return Signature().set(transformType, true);
        }

        template <typename T>
        const char *GetComponentName()
        {
            const char *typeName = typeid(T).name();
            assert(mComponentTypes.find(typeName) != mComponentTypes.end() && "Component not registered before use.");
            return typeid(T).name();
        }

        template <typename T>
        void AddComponent(Entity entity, T component)
        {
            GetComponentArray<T>()->InsertData(entity, component);
        }
        
        template <typename T>
        void RemoveComponent(Entity entity)
        {
            GetComponentArray<T>()->RemoveData(entity);
        }

        template <typename T>
        T &GetComponent(Entity entity)
        {
            return GetComponentArray<T>()->GetData(entity);
        }

        template <typename T>
        void SetComponent(Entity entity, T component)
        {
            GetComponentArray<T>()->SetData(entity, component);
        }

        void EntityDestroyed(Entity entity)
        {
            // 将每个ComponentArray中 该entity对应的Component删掉
            for (auto const &pair : mComponentArrays)
            {
                auto const &pComponentArr = pair.second;
                pComponentArr->EntityDestroyed(entity);
            }
        }
        // 根据类型获取ComponentArray
        template <typename T>
        std::shared_ptr<ComponentArray<T>> GetComponentArray()
        {
            const char *typeName = typeid(T).name();
            assert(mComponentTypes.find(typeName) != mComponentTypes.end() && "Component not registered yet.");
            return std::static_pointer_cast<ComponentArray<T>>(mComponentArrays[typeName]);
        }

    private:
        // ComponentType
        std::unordered_map<const char *, ComponentType> mComponentTypes{};
        // ComponentArray
        std::unordered_map<const char *, std::shared_ptr<IComponentArray>> mComponentArrays{};
        // 下一个将要注册的ComponentType
        ComponentType mNextComponentType{nullComponentType};  

    };
}
